/*
 * Copyright (C) 2008 by The Regents of the University of California
 * Redistribution of this file is permitted under the terms of the GNU
 * Public License (GPL).
 *
 * @author Junghoo "John" Cho <cho AT cs.ucla.edu>
 * @date 3/24/2008
 */

#include "BTreeIndex.h"
#include "BTreeNode.h"

using namespace std;

/*
 * BTreeIndex constructor
 */
BTreeIndex::BTreeIndex()
{
	treeHeight = 0;
    rootPid = -1;

}

void BTreeIndex::print(){
	printf("-----Dumping Tree Data-----\n");
	printf("Tree Height: %d \t Root PID: %d \n", treeHeight, rootPid);

}

/*
 * Open the index file in read or write mode.
 * Under 'w' mode, the index file should be created if it does not exist.
 * @param indexname[IN] the name of the index file
 * @param mode[IN] 'r' for read, 'w' for write
 * @return error code. 0 if no error
 */
RC BTreeIndex::open(const string& indexname, char mode)
{
	//Save the mode in order to know what to do when then index is closed.
	this->mode = mode;

	//Open the provided index file.
	if(pf.open(indexname, mode) != 0) {
		return RC_FILE_OPEN_FAILED;
	}

	//Copy the first page into a buffer to read information such as
	//tree height, and root page ID.
	char buffer[PageFile::PAGE_SIZE];
	if(pf.read(0, buffer) != 0) {
		return RC_FILE_READ_FAILED;
	}

	//If the index file was just created, we cannot read any more
	//information as it was not previously stored. So just exit.
	if(mode == 'w'){
		return 0;
	}

	//Read root page id.
	int offset = 0;
	memcpy(&rootPid, &buffer[offset], sizeof(PageId));
	offset += sizeof(PageId);

	//Read tree height.
	memcpy(&treeHeight, &buffer[offset], sizeof(int));
	offset += sizeof(int);

	return 0;
}

/*
 * Close the index file.
 * @return error code. 0 if no error
 */
RC BTreeIndex::close()
{
	if(this->mode == 'w'){
		char buffer[PageFile::PAGE_SIZE];

		int offset = 0;

		//Clear the buffer.
		memset(&buffer[offset], 0, PageFile::PAGE_SIZE);

		//Copy the root page ID into the buffer.
		memcpy(&buffer[offset], &rootPid, sizeof(PageId));
		offset += sizeof(PageId);

		//Copy the three height into the buffer.
		memcpy(&buffer[offset], &treeHeight, sizeof(int));
		offset += sizeof(int);

		//Write the buffer into the page file.
		if(pf.write(0, buffer) != 0) {
			return RC_FILE_WRITE_FAILED;
		}
	}

    return 0;
}

/*
 * Insert (key, RecordId) pair to the index.
 * @param key[IN] the key for the value inserted into the index
 * @param rid[IN] the RecordId for the record being inserted into the index
 * @return error code. 0 if no error
 */
RC BTreeIndex::insert(int key, const RecordId& rid)
{
    return 0;
}

/*
 * Find the leaf-node index entry whose key value is larger than or 
 * equal to searchKey, and output the location of the entry in IndexCursor.
 * IndexCursor is a "pointer" to a B+tree leaf-node entry consisting of
 * the PageId of the node and the SlotID of the index entry.
 * Note that, for range queries, we need to scan the B+tree leaf nodes.
 * For example, if the query is "key > 1000", we should scan the leaf
 * nodes starting with the key value 1000. For this reason,
 * it is better to return the location of the leaf node entry 
 * for a given searchKey, instead of returning the RecordId
 * associated with the searchKey directly.
 * Once the location of the index entry is identified and returned 
 * from this function, you should call readForward() to retrieve the
 * actual (key, rid) pair from the index.
 * @param key[IN] the key to find.
 * @param cursor[OUT] the cursor pointing to the first index entry
 *                    with the key value.
 * @return error code. 0 if no error.
 */
RC BTreeIndex::locate(int searchKey, IndexCursor& cursor)
{
	int retval = 0;

	if(treeHeight == 0) {
		cursor.pid = 1; //Page ID.
		cursor.eid = 0; //Entry ID.

		treeHeight++;
		rootPid = 1;

	} else if(treeHeight == 1) {

		//tree is of size 1, just a node at the root.
		BTLeafNode root;

		int eid;

		if( root.read(rootPid, pf) != 0) {
			return RC_FILE_READ_FAILED;
		}

		if( root.locate(searchKey, eid) != 0) {
			return RC_NO_SUCH_RECORD;
		}
		cursor.pid = rootPid;
		cursor.eid = eid;
	}

    return 0;
}

/*
 * Read the (key, rid) pair at the location specified by the index cursor,
 * and move foward the cursor to the next entry.
 * @param cursor[IN/OUT] the cursor pointing to an leaf-node index entry in the b+tree
 * @param key[OUT] the key stored at the index cursor location.
 * @param rid[OUT] the RecordId stored at the index cursor location.
 * @return error code. 0 if no error
 */
RC BTreeIndex::readForward(IndexCursor& cursor, int& key, RecordId& rid)
{
    return 0;
}
